home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-11 / exoapi.zip / EXOAPI.TXT < prev    next >
Text File  |  1993-06-15  |  44KB  |  1,042 lines

  1. ExoSpace version 1.0 API (revision #1)
  2. --------------------------------------
  3.  
  4. ExoSpace(tm) is based on the Rational DOS/16M(tm) 286 DOS Extender.  As a
  5. 286 DOS extender it executes 99% of the code written for real mode
  6. applications in protected mode.  In fact, as long as a few protected mode
  7. rules are followed converting an application to protected mode can be
  8. relatively easy.  Unfortunately, programmers who have no experience writing
  9. protected mode applications routinely break one of more of these rules and
  10. breaking just one rule in one location within a program can make the
  11. program unusable in protected mode.
  12.  
  13. The purpose of this document is to review protected mode rules, to
  14. demonstrate where protected mode programming is radically different from
  15. real mode programming, and to define the API functions available from
  16. ExoSpace that may be necessary to your C or Assembler functions.
  17.  
  18. When a program breaks one or more of the protected mode rules, a General
  19. Protection Fault or GP Fault occurs.  This causes ExoSpace to print out a
  20. message and abort the program back to DOS.  In truth, GP Faults are a
  21. terrific debugging tool.  They either show where you are breaking
  22. protected mode programming rules or they highlight bugs that would
  23. normally trash memory in real mode.
  24.  
  25. The quickest way to try to convert an application or third party library to
  26. protected mode is to link the application with ExoSpace creating a .MAP
  27. file with the "MAP A" command and then simply running the application to
  28. see if it works.  If it generates GP faults then you can look at the map
  29. file to see what module or function generated the fault.  You can then look
  30. at that module or function to see what caused the GP Fault.  In most cases
  31. you can narrow down any problems using this method.
  32.  
  33. It is also best to begin the process of conversion under plain DOS using a
  34. VCPI or XMS extended memory manager.  Do not begin by running in a Windows
  35. DOS box or under any other memory manager that only emulates the DPMI
  36. protocol.  This is because the DPMI protocol is much more restricting.
  37. When your program is not running under DPMI, it can expect the most used
  38. selector values to point to the same memory they do in real mode.  For
  39. example, when not under DPMI you can expect selectors 0xB000 and 0xB800 to
  40. point to video memory.  Once you have the application working under a
  41. non-DPMI manager you can then begin the process of making it compatible
  42. with DPMI by using the ExoProtectedPtr() function to create protected mode
  43. pointers to real mode addresses.
  44.  
  45. We also have a protected mode debugger available for those who have a
  46. great deal of work to do in making their code compatible with protected
  47. mode.  The debugger will halt the program on a GP fault allowing you to
  48. see exactly which instruction caused the problem.  If you are having a
  49. great deal of trouble tracking down problems in your code, please contact
  50. us about the debugger.
  51.  
  52. We also suggest that you take some time to read a few books about
  53. protected mode programming with DOS extenders.  Your current code may be
  54. easy to convert to protected mode (some code may require absolutely no
  55. changes, especially C code), but protected mode programming is the future
  56. direction DOS will take and it may be useful to be more familiar with it.
  57. The book we found helpful was:
  58.  
  59. Extending DOS
  60. Ray Duncan
  61. Addison Wesley Publishing
  62. ISBN 0-201-56798-9
  63. (The first edition uses the Rational DOS/16M extender and the second
  64. edition uses the PharLap 286 DOS extender.)
  65.  
  66.  
  67.  
  68. Protected Mode Rules
  69. --------------------
  70.  
  71. 1) A selector value (referred to as a segment value in real mode) loaded
  72. into DS, ES, SS, and CS actually references a "chunk" of memory that may
  73. occur anywhere within the physical address space and can even be moved
  74. around by the operating system.  Therefore, when dealing with selector
  75. values:
  76.  
  77. a) Never load DS or ES with "junk" values or a GP fault may occur.  Never
  78. use DS or ES as "scratch" registers that can be loaded with arbitrary
  79. values.  Everytime DS and ES is loaded with a value the microprocessor
  80. checks to make sure it is a valid selector value and generates a GP fault
  81. if it is not.
  82.  
  83. b) Never perform "segment arithmetic" on a selector value.  This is done in
  84. real mode code to either "normalize" a pointer or to access data that is
  85. greater than 64K in size.  A selector value is a unique ID which has no
  86. relationship to the data it points to.
  87.  
  88. c) All selectors have a size associated with them and attempts to
  89. access data at an offset greater than that size will result in a GP
  90. fault.  This is one of the greatest strengths of a 286 DOS Extender because
  91. most obscure bugs in real mode code occur when a "wild pointer" is used.
  92. This will usually cause a GP fault in protected mode because either the
  93. selector or offset value will be invalid.
  94.  
  95. d) DS and ES can be loaded with a selector value of 0 (a NULL pointer in C
  96. parlance), but never try to write to or read from a NULL pointer.  A great
  97. deal of C code has this mistake in it.  Attempts to read from or write to a
  98. NULL pointer will generate a GP fault.
  99.  
  100. e) Segment values in real mode always point to a physical address equal to
  101. the segment value multiplied by 16, but selector values in protected mode
  102. may point to anywhere in memory.  Therefore, you cannot assume standard
  103. addresses such as 0xB000 and 0xB800 (used to address a monochrome or color
  104. screen) will point to the same memory they do in protected mode.  In truth,
  105. under DPMI only selector 0x40 is guaranteed to point to the BIOS data area
  106. - no other selector value is predefined.  For maximum portability you will
  107. have to use the ExoProtectedPtr() function to address absolute physical
  108. addresses.
  109.  
  110. 2) You cannot execute code in a data segment and you cannot write to data
  111. in the code segment.
  112.  
  113. 3) ExoSpace handles most of the standard DOS interrupts transparently, but
  114. when passing pointers to buffers to software interrupt calls not handled
  115. transparently by ExoSpace, the buffers must exist in low DOS memory and
  116. the pointers must be converted from protected mode selector:offset pairs
  117. to real mode segment:offset pairs.
  118.  
  119.  
  120.  
  121.  
  122. ExoSpace errata
  123. ---------------
  124.  
  125. Although ExoSpace does provide a DOS protected mode version of the
  126. int86/intdos() functions, they cannot be used when calling a real mode
  127. interrupt which returns a value in DS or ES.  Real mode segment values
  128. stored in DS or ES are invalid in protected mode.  When a real mode
  129. interrupt modifies DS or ES in an int86/intdos() call, ExoSpace will most
  130. likely replace the value with a 0 to prevent a GP fault.  Use of
  131. ExoRMInterrupt() is always preferred because it should be slightly faster
  132. than the int86/intdos() functions and will return the real mode values of
  133. DS and ES.
  134.  
  135. In 286 protected mode, the IN and OUT instructions work the same as they
  136. do in real mode.  No special handling of the I/O ports in necessary.
  137.  
  138. Under ExoSpace, the PSP is the same as it is in real mode.  It is located
  139. in low DOS memory so both DOS and ExoSpace have access to it.  All of the
  140. pointer values are real mode values except for the segment address of the
  141. environment at offset 0x2C.
  142.  
  143. The DOS16M environment variable can be used to restrict the amount of
  144. memory ExoSpace uses.  This can be used to test your applications with
  145. various amounts of memory.  For example, to test your application under a
  146. 2MB configuration use "SET DOS16M=:2MB" (be sure to use the :).
  147.  
  148.  
  149.  
  150.  
  151. Interrupts
  152. ----------
  153.  
  154. Many interrupts are handled "transparently" by ExoSpace especially the DOS
  155. function interrupt 0x21.  Interrupts not handled transparently by ExoSpace
  156. can safely be called as long as they don't pass pointers to buffers or
  157. return pointers to data.  A brief breakdown of some of the important
  158. interrupts follows:
  159.  
  160. Interrupt 0x08 (System Clock):  If you install a handler with interrupt
  161. 0x21, function 0x25, ExoSpace will automatically call your interrupt
  162. handler in protected mode.  Interrupt 0x1C handlers are NOT called.
  163.  
  164. Interrupt 0x1C (User Timer Tick): Install a handler for interrupt 8
  165. instead.
  166.  
  167. Interrupt 0x0B-0C (Serial port interrupts): If a handler is installed with
  168. interrupt 0x21, function 0x25, ExoSpace will automatically call your
  169. interrupt handler.  If you are doing high-speed interrupt-driven
  170. communications you will need to install bi-modal interrupt functions.
  171.  
  172. Interrupt 0x10 (Video BIOS): Because the majority of video BIOS interrupts
  173. do not pass pointers to buffers, the majority of them work just fine with
  174. ExoSpace.  Of those functions which do pass pointers to buffers, the
  175. following are handled transparently by ExoSpace WITHOUT the INT10 package:
  176. function 0x10, subfunctions 0x02, 0x09; function 0x13; function 0x1B;
  177. function 0x1C, subfunctions 0x01, 0x02.
  178.  
  179. Interrupt 0x16 (Keyboard): These interrupts are handled transparently by
  180. ExoSpace, but function 0x01 and 0x11 are handled specially.  Because these
  181. interrupts are resignaled in real mode and because doing a mode switch
  182. takes time, these interrupts are only signaled in real mode every timer
  183. tick (1/18th of a second) or after a call to interrupt 0x16, functions 0x00
  184. or 0x10.  This optimization helps performance.
  185.  
  186. Interrupt 0x21 (DOS): Most of the documented interrupts are fully
  187. supported.  Functions that require special notes are:
  188.  
  189.    0x1F (Get DPB) - You must use ExoProtectedPtr() to translate the real
  190.         mode address returned in DS:BX by this function.
  191.  
  192.    0x26 (Create PSP) - Pass return value from ExoRealPtr().
  193.  
  194.    0x2A (Get date) - The real mode interrupt is resignaled only once every
  195.         timer tick to help performance.
  196.  
  197.    0x2C (Get time) - The real mode interrupt is resignaled only once every
  198.         timer tick to help performance.
  199.  
  200.    0x44 (IOCTL) - subfunction 0x0C, minor codes 0x45 and 0x65; and
  201.         subfunction 0x0D, minor codes 0x40 - 0x42, 0x60 - 0x62 are not
  202.         translated.  Use ExoRealPtr() to translate any addresses passed to
  203.         the functions, use ExoRMInterrupt() to call the functions, and use
  204.         ExoProtectedPtr() to translate any return addresses.
  205.  
  206.    0x48 (Allocate Memory) - Memory is most likely allocated from extended
  207.         extended memory and the returned value in AX is a protected mode
  208.         selector.  It is recommended that you use Clipper's memory
  209.         allocation functions.
  210.  
  211.    0x50 to 0x53, 0x55, 0x5C, 0x5D - These functions are not transparently
  212.         supported.  Use ExoRealPtr() to translate any addresses passed to
  213.         the functions, use ExoRMInterrupt() to call the functions, and use
  214.         ExoProtectedPtr() to translate any return addresses.
  215.  
  216. Interrupts 0x25 and 0x26 (Absolute Disk Read/Write): These interrupts ARE
  217. NOT handled transparently by ExoSpace.  To use these interrupts you MUST
  218. link in the DOS25 package.  When this package is linked in, the interrupts
  219. are handled transparently.
  220.  
  221. Interrupt 0x31 (DPMI): When running under a DPMI host, all DPMI calls are
  222. passed on to the host.  When the program is not running under a DPMI host,
  223. ExoSpace provides a handler for some of the most common DPMI calls: 0 - 3,
  224. 6 - C, 100 - 102, 200, 201, 204, 205, 300 - 304, 400, 500 - 503, 800, 801,
  225. 900 - 902 (all values are in hex).
  226.  
  227. Interrupt 0x33 (Mouse): This interrupt is NOT handled transparently by
  228. ExoSpace.  To use this interrupt you MUST link in the MOUSE package.  When
  229. the MOUSE package is linked in, all functions are supported except for
  230. functions 0x18, 0x19, 0x1F, 0x20.
  231.  
  232. Interrupt 0x5C (NetBIOS): This interrupt is NOT handled transparently by
  233. ExoSpace.  To use this interrupt you MUST link in the NET5C package.  When
  234. the NET5C package is linked in, all functions are supported except for
  235. functions 0x71 and 0x72.
  236.  
  237. Interrupt 0x7A (IPX/SPX): This interrupt is NOT handled transparently by
  238. ExoSpace.  To use this interrupt you MUST link in the IPX package.  When
  239. the IPX package is linked in, all functions are supported.
  240.  
  241. Interrupt 0x7F (8514/A): This interrupt is NOT handled transparently by
  242. ExoSpace.  To use this interrupt you MUST link in the 8514 package.  When
  243. the 8514 package is linked in, all functions are supported.
  244.  
  245. Interrupts 0xF0 - 0xFF: These interrupts are reserved for use by ExoSpace.
  246.  
  247.  
  248.  
  249.  
  250. Packages
  251. --------
  252.  
  253. ExoSpace packages contain additional support for interrupts which pass
  254. pointers to buffers.  The packages and what they support are listed below.
  255.  
  256. INT10 - This package provides support for the video BIOS interrupts 0x10,
  257. 0x11, and 0x12.  Function 0x10, subfunctions 0x12 and 0x17 are supported.
  258. Function 0x11, subfunctions 0x00, 0x10, 0x20, 0x21 are supported with the
  259. warning that the support is not fully tested.  Function 0x12, subfunctions
  260. 0x00, 0x02, and 0x03 are supported with the warning that the support is not
  261. fully tested.  Function 0x5F, subfunctions 0x91 and 0x92 are supported.
  262. Functions 0xF2 to 0xF5 and 0xF7 (the Microsoft mouse EGA support functions)
  263. are supported.
  264.  
  265. DOS25 - This package provides support for the absolute disk read/write
  266. interrupts 0x25 and 0x26.  Attempts to call these interrupts in an
  267. ExoSpace'd application without this package linked in will result in
  268. undesirable behavior.
  269.  
  270. MOUSE - This package provides support for the Microsoft mouse interrupt
  271. 0x33 functions except for functions 0x18, 0x19, 0x1F, 0x20.  Attempts to
  272. call many of the mouse functions in an ExoSpace'd application without this
  273. package linked in will result in undesirable behavior.
  274.  
  275. NET5C - This package provides support for the NetBIOS interrupt 0x5C
  276. functions except for functions 0x71 and 0x72.  Attempts to call the NetBIOS
  277. functions in an ExoSpace'd application without this package linked in will
  278. result in undesirable behavior.
  279.  
  280. IPX - This package provides support for IPX/SPX.  Attempts to call the IPX
  281. functions in an ExoSpace'd application without this package linked in will
  282. result in undesirable behavior.  There has been one report of a problem
  283. with this package.  We are interested in hearing from anyone using this
  284. package.
  285.  
  286. 8514 - This package provides support for the IBM 8514 Display Adapter.
  287. Attempts to call the 8514 functions in an ExoSpace'd application without
  288. this package linked in will result in undesirable behavior.
  289.  
  290. NOVM - This is not a package, but a switch to tell ExoSpace not to link in
  291. the ExoSpace VM system which uses the Rational DOS/16M VMM system.  This
  292. switch is currently necessary to create executables that can be debugged
  293. with Rational's protected mode debugger.  Otherwise, this switch is not
  294. currently recommended because it not only disables code and data swapping,
  295. but it also inhibits memory compaction.
  296.  
  297.  
  298.  
  299.  
  300. API Library Functions
  301. ---------------------
  302.  
  303. The ExoSpace API library functions are all C callable functions and are
  304. documented below as C prototypes.  The Rational DOS/16M 286 DOS Extender
  305. has a rich set of API functions and we have chosen to emulate a small
  306. subset of the most useful functions in our API.  This API should satisfy 9
  307. out of 10 developers doing C or Assembler programming.
  308.  
  309. We will probably be providing a real mode "stub" library in the next few
  310. weeks for those who wish to try to create a "bimodal" library that works
  311. with and without ExoSpace.  This "stub" library will contain dummy ExoSpace
  312. API functions which will return values expected for non-ExoSpace'd real
  313. mode code.  You will be able to freely add this library to your own
  314. library.  Thus, when linking with ExoSpace the ExoSpace API functions will
  315. be linked in and when using a real mode linker such as Blinker or RTLink
  316. the "stub" functions will be linked in from your library.
  317.  
  318.  
  319. /* definition needed for ExoRMInterrupt() below */
  320. typedef struct _exoregs {
  321.     unsigned ds, es;
  322.     unsigned di, si, bp, sp;    /* note: sp is ignored */
  323.     unsigned bx, dx, cx, ax;
  324.     } EXOREGS;
  325.  
  326. int    ExoFreeSelector(unsigned int selector);
  327. int    ExoIsDPMI(void);
  328. int    ExoIsExoSpace(void);
  329. int    ExoIsPM(void);
  330. int    ExoIsVMM(void);
  331. void  *ExoProtectedPtr(void *rmptr, unsigned int sizebytes);
  332. void  *ExoRealPtr(void *pmptr);
  333. int    ExoReside(void *pmptr);
  334. int    ExoRMInterrupt(int, EXOREGS *inregs, EXOREGS *outregs);
  335. void (*ExoSegCSAlias(void *pmptr))();
  336. void  *ExoSegDSAlias(void *pmptr());
  337. void  *_xalloclow(unsigned int sizebytes);
  338. void   _xfreelow(void *lowmemory);
  339.  
  340.  
  341.  
  342. ExoFreeSelector()
  343.  
  344.  Purpose: Cancels a protected mode segment descriptor created by
  345.           ExoProtectedPtr(), ExoSegCSAlias(), or ExoSegDSAlias().
  346.  
  347.   Syntax: int ExoFreeSelector(unsigned int selector);
  348.  
  349.  Returns: Always returns 0.
  350.  
  351. See also: ExoProtectedPtr(), ExoSegCSAlias(), or ExoSegDSAlias()
  352.  
  353.    Notes: This function is a primitive function; it corresponds to the DPMI
  354.           function that cancels a descriptor.
  355.  
  356.           This function must be passed only the selector part of a pointer
  357.           created with ExoProtectedPtr(), ExoSegCSAlias(), or
  358.           ExoSegDSAlias().
  359.  
  360.           Because selectors are a limited resource in protected mode (there
  361.           are "usually" around 8000 available for code and data segments),
  362.           you should free selectors you have created with
  363.           ExoProtectedPtr(), ExoSegCSAlias(), or ExoSegDSAlias() as soon as
  364.           you are done with them.
  365.  
  366.           We had intended to include the API function ExoSegCancel() which
  367.           would accept a pointer instead of just the selector portion of a
  368.           pointer, but it was inadvertently left out.  A future revision of
  369.           the API will include this function.
  370.  
  371.  Example: This code creates a protected mode pointer to video color memory,
  372.           does some unknown operation with it and then frees the protected
  373.           mode selector.
  374.  
  375.           void *rmvideo;
  376.           void *pmvideo;
  377.  
  378.           /* set up pointer to point to real mode address 0xB800:0 which
  379.              is the address of the color video card */
  380.           FP_SEG(rmvideo) = 0xB800;
  381.           FP_OFF(rmvideo) = 0;
  382.  
  383.           /* create protected mode pointer for use in protected mode */
  384.           pmvideo = ExoProtectedPtr(rmvideo, 0x8000);
  385.  
  386.           ... more code using pmvideo pointer would normally be here ...
  387.  
  388.           /* free up selector used by pmpointer now that we are done
  389.              with it */
  390.           ExoFreeSelector(FP_SEG(pmvideo));
  391.  
  392.  
  393.  
  394. ExoIsDPMI()
  395.  
  396.  Purpose: Returns true if running in a DPMI host environment.
  397.  
  398.   Syntax: int ExoIsDPMI(void);
  399.  
  400.  Returns: This function returns nonzero if the program is running in a DPMI
  401.           host. If the program is not running under DPMI, ExoIsDPMI returns
  402.           zero.
  403.  
  404. See also: ExoIsExoSpace(), ExoIsPM()
  405.  
  406.    Notes: Use this function to determine whether your program is running
  407.           under a DPMI host, such as Windows 3.x in enhanced mode.
  408.  
  409.  Example: This program fragment prints a message telling whether or not the
  410.           program executing is running under DPMI.
  411.  
  412.           if (ExoIsDPMI())
  413.              printf("Program is running under DPMI");
  414.           else
  415.              printf("Program is not running under DPMI");
  416.  
  417.  
  418.  
  419. ExoIsExoSpace()
  420.  
  421.  Purpose: Returns true if running under ExoSpace.
  422.  
  423.   Syntax: int ExoIsExoSpace(void);
  424.  
  425.  Returns: This function returns nonzero if an ExoSpace program is running.
  426.  
  427. See also: ExoIsDPMI(), ExoIsPM()
  428.  
  429.    Notes: Use this function to determine whether your program is running
  430.           under ExoSpace.  If the program has been linked with the real
  431.           mode "stub" library, this function will return zero.
  432.  
  433.  Example: This program fragment prints a message telling whether or not the
  434.           program executing is an ExoSpace application.
  435.  
  436.           if (ExoIsExoSpace())
  437.              printf("ExoSpace program is running");
  438.           else
  439.              printf("ExoSpace program is not running");
  440.  
  441.  
  442.  
  443. ExoIsPM()
  444.  
  445.  Purpose: Returns true if the CPU is running in protected mode.
  446.  
  447.   Syntax: int ExoIsPM(void);
  448.  
  449.  Returns: Nonzero if the CPU is executing in protected mode, zero
  450.   otherwise.
  451.  
  452. See Also: ExoIsDPMI(), ExoIsExoSpace()
  453.  
  454.    Notes: Use this function to determine whether the processor is
  455.   running in protected mode.
  456.  
  457.  Example: This program fragment prints a message telling whether or
  458.   not the CPU is in protected mode.
  459.  
  460.           if (ExoIsPM())
  461.              printf("cpu is in protected mode");
  462.           else
  463.              printf("cpu not in protected mode");
  464.  
  465.  
  466.  
  467. int  ExoIsVMM(void);
  468.  
  469.  Purpose: Returns true if the ExoSpace program is using the ExoSpace VMM
  470.           system.
  471.  
  472.   Syntax: int ExoIsVMM(void);
  473.  
  474.  Returns: Nonzero if the program is using the ExoSpace VMM system, zero
  475.           otherwise.
  476.  
  477. See Also: ExoIsDPMI(), ExoIsExoSpace()
  478.  
  479.    Notes: Use this function to determine whether the ExoSpace VMM system is
  480.           active.  It will not be active if the option "EXOSPACE PACKAGE
  481.           NOVM" was specified during the link or if you are running under a
  482.           DPMI server such as a Windows or OS/2 DOS box.
  483.  
  484.  Example: This program fragment prints a message telling whether or not the
  485.           program is using the ExoSpace VMM system.
  486.  
  487.           if (ExoIsVMM())
  488.              printf("program is using the ExoSpace VMM system");
  489.           else
  490.              printf("program is not using the ExoSpace VMM system");
  491.  
  492.  
  493.  
  494. ExoProtectedPtr()
  495.  
  496.  Purpose: Creates a protected mode pointer from a real mode pointer.
  497.  
  498.   Syntax: void *ExoProtectedPtr(void *rm_ptr, unsigned size);
  499.  
  500.  Returns: The protected mode pointer, or NULL if the pointer can't be
  501.           allocated. A new descriptor is allocated.
  502.  
  503. See also: ExoRealPtr(), ExoFreeSelector()
  504.  
  505.    Notes: The protected mode data pointer created by this function points
  506.           to a segment of size bytes.  Since a value of 64KB is too large
  507.           for an unsigned variable, use 0 to specify 64KB for size. The
  508.           offset of pm_ptr is always 0.  The base physical address of
  509.           pm_ptr's segment is the absolute address of rm_ptr, which is
  510.           segment(rm_ptr) * 16 + offset(rm_ptr).  Because ExoProtectedPtr()
  511.           is run with interrupts enabled, realtime applications should not
  512.           call it from an external interrupt handler.
  513.  
  514.           The offset of the pointer returned by ExoProtectedPtr() will
  515.           ALWAYS be 0.
  516.  
  517.           ExoFreeSelector() MUST be called to free the selector allocated
  518.           with ExoProtectedPtr().  Selectors are a limited resource and
  519.           repeated calls to ExoProtectedPtr() as well as ExoSegCSAlias()
  520.           and ExoSegDSAlias() could use up all the available selectors
  521.           causing the program to crash.  Once you are done with a pointer
  522.           created with ExoProtectedPtr(), free the selector unless you'll
  523.           be using the pointer thoughout the program.
  524.  
  525.  Example: See example for ExoFreeSelector().
  526.  
  527.  
  528.  
  529. ExoRealPtr()
  530.  
  531.  Purpose: Creates a real mode pointer from a protected mode pointer.
  532.  
  533.   Syntax: void *ExoRealPtr(void *pm_ptr);
  534.  
  535.  Returns: The real mode pointer, or NULL if pm_ptr is in extended memory
  536.           (not accessible in real mode).
  537.  
  538. See also: ExoProtectedPtr()
  539.  
  540.    Notes: The pm_ptr argument is the protected mode pointer to be
  541.           converted. Note that if the real mode pointer is 0:0, the
  542.           returned value is the same as an error value.
  543.  
  544.  Example: See example for _xalloclow().
  545.  
  546.  
  547.  
  548. ExoReside()
  549.  
  550.  Purpose: Flags a VMM segment to remain resident in memory.
  551.  
  552.   Syntax: int ExoReside(void *pmptr);
  553.  
  554.  Returns: -1 on error, 0 or 1 otherwise.
  555.  
  556. See also: ExoSegDSAlias()
  557.  
  558.    Notes: When the VMM system is active a code or data segment may be
  559.           swapped out at any time.  When data segments are swapped out they
  560.           are always written to the swap file, but code segments are never
  561.           written to the swap file when they are swapped out unless a data
  562.           segment alias created by ExoSegDSAlias() exists at the time the
  563.           code segment is swapped out.  If you write to a data segment
  564.           alias of a code segment when ExoSpace's VMM is active, you will
  565.           need to mark the segment as resident before freeing the data
  566.           segment alias with ExoFreeSelector().
  567.  
  568.  Example: See example for ExoSegDSAlias().
  569.  
  570.  
  571.  
  572. ExoRMInterrupt()
  573.  
  574.  Purpose: Sets the registers, then signals a real mode interrupt.
  575.  
  576.   Syntax: int ExoRMInterrupt(int intno, EXOREGS *inregs, EXOREGS *outregs);
  577.  
  578.  Returns: The flags register.
  579.  
  580. See also: None
  581.  
  582.    Notes: Use ExoRMInterrupt() to signal a real mode interrupt that
  583.           requires you to set registers. This function allows you to set
  584.           real mode segment register values from protected mode. When you
  585.           use regular passdown interrupts, you can't set real mode register
  586.           values.
  587.  
  588.           A call to ExoRMInterrupt() sets the registers to the values you
  589.           provide in the structure to which inregs points; then it invokes
  590.           interrupt intno.  After the interrupt is processed,
  591.           ExoRMInterrupt() stores the register values in the structure
  592.           pointed to by outregs.  The structures pointed to by inregs and
  593.           outregs are both type EXOREGS.  Note that you cannot set the SS
  594.           and SP registers from a EXOREGS structure.
  595.  
  596.           Before ExoSpace signals the specified interrupt, it sets the CPU
  597.           flags to the value they had when you called ExoRMInterrupt() in
  598.           protected mode.  Notice that the value of the flags register
  599.           after the real mode interrupt call is made is returned by this
  600.           function.
  601.  
  602.           When you use ExoRMInterrupt(), there must be a return from the
  603.           real mode interrupt to match every call (unless your program is
  604.           terminating).  Also, if reentrance on ExoRMInterrupt() is
  605.           possible, the interrupt should use less than 256 bytes of stack.
  606.           You can get around this limit by switching to a different stack
  607.           in the real mode handler/function.
  608.  
  609.  Example: This example signals DOS function 2Ch to get the time of day. As
  610.           required for that call, the high order byte of the AX register is
  611.           set to 2Ch.  Note that the structure EXOREGS does not contain a
  612.           field AH, so you must set the high order byte using the shift
  613.           operator (<<).  After the call to ExoRMInterrupt(), this example
  614.           displays the contents of the outreg registers. The display shows
  615.           the time in hours, minutes and seconds. Since the hours and
  616.           seconds are stored in the high order byte, the shift operator is
  617.           used again.
  618.  
  619.           int main()
  620.           {
  621.              EXOREGS inreg;
  622.              EXOREGS outreg;
  623.  
  624.               inreg.ax = 0x2C << 8;
  625.  
  626.               /* DOS function "get time" - signal int 21h */
  627.               ExoRMInterrupt(0x21, &inreg, &outreg);
  628.  
  629.               printf("The time is %d:%02d:%02d\n",
  630.                 outreg.cx >> 8, outreg.cx&0xFF, outreg.dx >> 8);
  631.           }
  632.  
  633.  
  634.  
  635. ExoSegCSAlias()
  636.  
  637.  Purpose: Creates a code descriptor for the given data segment.
  638.  
  639.   Syntax: void (*ExoSegCSAlias(void *pm_ptr))();
  640.  
  641.  Returns: A function pointer to the same linear address as pm_ptr, or NULL
  642.           if an error occurred.
  643.  
  644. See also: ExoSegDSAlias()
  645.  
  646.    Notes: The new descriptor created by ExoSegCSAlias points to the segment
  647.           base of pm_ptr.  This function enables you to execute code in a
  648.           data segment.  To store data in a code segment, use
  649.           ExoSegDSAlias().  Because ExoSegCSAlias() is run with interrupts
  650.           enabled, realtime applications should not call it from an
  651.           external interrupt handler.
  652.  
  653.           The offset of the alias will ALWAYS equal the offset of the
  654.           original pointer.
  655.  
  656.           ExoFreeSelector() MUST be called to free the selector allocated
  657.           with ExoSegCSAlias().  Selectors are a limited resource and
  658.           repeated calls to ExoSegCSAlias() as well as ExoSegDSAlias()
  659.           and ExoProtectedPtr() could use up all the available selectors
  660.           causing the program to crash.  Once you are done with a pointer
  661.           created with ExoSegCSAlias(), free the selector unless you'll
  662.           be using the pointer thoughout the program.
  663.  
  664.  Example: This code fragment calls executable machine code written by the
  665.           program to a data buffer.
  666.  
  667.           char writablecode[100];
  668.           void (*funcptr(void));
  669.  
  670.           /* during execution the program would write executable machine
  671.              code to the 100 byte writablecode buffer */
  672.           ...
  673.  
  674.           /* create a selector that is a code segment alias to the data
  675.              segment containing the variable writablecode */
  676.           funcptr = ExoSegCSAlias(writablecode);
  677.  
  678.           /* set the offset of the function pointer to the offset of the
  679.              writablecode buffer */
  680.           FP_OFF(funcptr) = FP_OFF(writablecode);
  681.  
  682.           /* call the code written to the writablecode buffer */
  683.           *funcptr();
  684.  
  685.           /* cancel the code segment selector */
  686.           ExoFreeSelector(FP_SEG(funcptr));
  687.  
  688.  
  689.  
  690. ExoSegDSAlias()
  691.  
  692.  Purpose: Creates a data descriptor for the given code segment.
  693.  
  694.   Syntax: void *ExoSegDSAlias(void *pm_ptr());
  695.  
  696.  Returns: A data pointer to the same linear address as pm_ptr, or NULL if
  697.           an error occurred.
  698.  
  699. See also: ExoSegCSAlias()
  700.  
  701.    Notes: This function creates a new data descriptor with the same base as
  702.           the segment specified by pm_ptr.  After the call to
  703.           ExoSegDSAlias(), the descriptor indicated in pm_ptr still exists
  704.           and retains its original segment type.
  705.  
  706.           The offset of the alias will ALWAYS equal the offset of the
  707.           original pointer.
  708.  
  709.           ExoFreeSelector() MUST be called to free the selector allocated
  710.           with ExoSegDSAlias().  Selectors are a limited resource and
  711.           repeated calls to ExoSegDSAlias() as well as ExoSegCSAlias()
  712.           and ExoProtectedPtr() could use up all the available selectors
  713.           causing the program to crash.  Once you are done with a pointer
  714.           created with ExoSegDSAlias(), free the selector unless you'll
  715.           be using the pointer thoughout the program.
  716.  
  717.  Example: The example below consists of two modules: one in assembly
  718.           language and one in C. The int_instruction label in the assembly
  719.           code marks the location of an instruction signaling Interrupt 0h.
  720.           The C code overwrites this instruction so that a different
  721.           interrupt is signaled.
  722.  
  723.           The C code calls ExoSegDSAlias() to get an alias data pointer to
  724.           int_instruction. The example then increments the pointer by one
  725.           byte to point to the location of "0h" in the instruction. The
  726.           example overwrites this location with "0x88" and frees the data
  727.           descriptor with ExoFreeSelector() since it is no longer needed.
  728.  
  729.           public _do_int, int_instruction
  730.           _do_int:
  731.           ...
  732.           int_instruction:
  733.           int 0h
  734.           ...
  735.  
  736.           char *data;
  737.           extern int_instruction();
  738.  
  739.           /* create data segment alias and write interrupt number 0x88 */
  740.           data = ExoSegDSAlias(int_instruction);
  741.           *(data + 1) = 0x88;
  742.  
  743.           /* mark code segment as resident so the VMM system won't swap it
  744.              out and lose the changes made to it */
  745.           ExoReside(int_instruction);
  746.  
  747.           /* free the selector created by ExoSegDSAlias() since we don't
  748.              need it anymore */
  749.           ExoFreeSelector(FP_SEG(data));
  750.  
  751.  
  752.  
  753. _xalloclow()
  754.  
  755.  Purpose: Allocates low DOS memory for use with real mode interrupts that
  756.           must be passed buffers within the first 1 MB.
  757.  
  758.   Syntax: void *_xalloclow(unsigned int sizebytes);
  759.  
  760.  Returns: A protected mode pointer to the allocated memory.
  761.  
  762. See also: ExoRealPtr(), ExoRMInterrupt(), _xfreelow()
  763.  
  764.    Notes: This function returns a protected mode pointer to the allocated
  765.           memory.  Use this pointer to write to or read from the allocated
  766.           buffer.  When calling a real mode interrupt you must get a real
  767.           mode pointer to the allocated buffer with the ExoRealPtr()
  768.           function and pass that address in the EXOREGS structure of a
  769.           ExoRMInterrupt() call.
  770.  
  771.           You can allocate a 64K buffer by passing a size of 0.
  772.  
  773.           You must use _xfreelow() to free memory allocated with this
  774.           function.  Do not use xfree()!
  775.  
  776.           It is suggested that you free the allocated low DOS memory as
  777.           soon as possible to keep down the amount of low DOS memory that
  778.           may be allocated at the same time not only by your functions
  779.           but also by other C/ASM code or by other third party libraries.
  780.  
  781.           ExoSpace has added the LOWMEM parameter to the CLIPPER
  782.           environment variable to allow a developer to set aside low DOS
  783.           memory for allocation with _xalloclow().  The LOWMEM parameter
  784.           does not have to be specified in order for _xalloclow() to work;
  785.           if there is no available low DOS memory when _xalloclow() is
  786.           called, ExoSpace will free up low DOS memory it uses in order to
  787.           meet the request.  At this time because of the current design of
  788.           ExoSpace's memory allocation scheme we recommend that you ignore
  789.           the LOWMEM parameter.  Future revisions or individual end-user
  790.           needs may make the LOWMEM parameter more necessary.
  791.  
  792.  Example: This example maps a fake root directory of a specified drive
  793.           under Novell NetWare.  The function below accepts a drive number
  794.           (0=default, 1=A:, ...) and path for fake root; it returns
  795.           zero on success and an error code if the function failed.
  796.  
  797.           int maproot(int drive, char *path)
  798.           {
  799.              int returnvalue = 0xFFFF;
  800.              int flags;
  801.              char *buffer;
  802.              char *realptr;
  803.              EXOREGS inoutregs;
  804.  
  805.              /* allocate low memory buffer to store path */
  806.              if ((buffer = _xalloclow(strlen(path) + 1)) != NULL)
  807.              {
  808.                 /* store path in low memory buffer */
  809.                 strcpy(buffer, path);
  810.  
  811.                 /* get real mode pointer to low memory buffer */
  812.                 if ((realptr = ExoRealPtr(buffer)) != NULL)
  813.                 {
  814.                    /* fill in EXOREGS structure */
  815.                    inoutregs.ax = 0xE905;
  816.                    inoutregs.bx = drive;
  817.                    inoutregs.ds = FP_SEG(realptr);
  818.                    inoutregs.dx = FP_OFF(realptr);
  819.  
  820.                    /* call the real mode interrupt */
  821.                    flags = ExoRMInterrupt(0x21, &inoutregs, &inoutregs);
  822.  
  823.                    /* see if carry flag is set to indicate error */
  824.                    if (flags & 0x0001)
  825.                       /* return error code in al */
  826.                       returnvalue = (inoutregs.ax & 0x00FF);
  827.                    else
  828.                       /* return no error code */
  829.                       returnvalue = 0;
  830.                 }
  831.  
  832.                 /* free low memory buffer */
  833.                 _xfreelow(buffer);
  834.              }
  835.           }
  836.  
  837.  
  838.  
  839. _xfreelow()
  840.  
  841.  Purpose: Frees memory allocated by _xalloclow().
  842.  
  843.   Syntax: void _xfreelow(void *lowmemory);
  844.  
  845.  Returns: Nothing.
  846.  
  847. See also: _xalloclow()
  848.  
  849.    Notes: You must use this function to free memory allocated by
  850.           _xalloclow().  Do not use xfree() to free memory allocated by
  851.           _xalloclow()!
  852.  
  853.  Example: See _xalloclow() example.
  854.  
  855.  
  856.  
  857.  
  858. Problem Solving
  859. ---------------
  860.  
  861. Question: How do I determine if I am running under ExoSpace?
  862.  
  863. Answer: Simply use the ExoIsExoSpace() function.
  864.  
  865.  
  866.  
  867. Question: How do I determine if I am running in protected mode?
  868.  
  869. Answer: Simply use the ExoIsPM() function.  This function has little use
  870. because ExoSpace does not document a way to switch to real mode.
  871.  
  872.  
  873.  
  874. Question: How do I determine if Rational's VM system is active?
  875.  
  876. Answer: Simply use the ExoIsVMM() function.  If the application was
  877. created with the "EXOSPACE PACKAGE NOVM" option, this function will return
  878. zero (false).
  879.  
  880.  
  881.  
  882. Question: How do I determine if I am running under DPMI?
  883.  
  884. Answer: Simply use the ExoIsDPMI() function.  Running under DPMI is more
  885. restrictive than running under any other memory manager and although you
  886. should construct your software to run under DPMI you could choose to
  887. restrict your software to run under non-DPMI memory managers.
  888.  
  889.  
  890.  
  891. Question: I really need to write to data in the code segment.  How can I do
  892. so?
  893.  
  894. Answer: You can write data to the code segment is you create a "DS alias".
  895. You can NEVER write to the code segment using the CS selector register,
  896. but you can create an alias using the ExoDSAlias() function.  This
  897. function returns a selector that can be loaded into the DS or ES
  898. registers.  This selector points to the same memory used as a code segment.
  899.  
  900.  
  901.  
  902. Question: I really need to execute code I have created in a data segment.
  903. How can I do so?
  904.  
  905. Answer: You can use the ExoCSAlias() to create a code selector that
  906. corresponds to a data segment.  You can then CALL or JMP to the code
  907. selector.
  908.  
  909.  
  910.  
  911. Question: I want to address an absolute memory location such as the color
  912. video memory at 0xB8000.  How do I do so?
  913.  
  914. Answer: When not running under DPMI, many of the most used real mode
  915. segments are matched by protected mode selectors that are mapped to the
  916. same physical memory locations.  When running under DPMI (such as in a
  917. Windows DOS box) the only selector that is predefined to match its real
  918. mode segment is selector 0x40 which points to the BIOS data area.  Under
  919. DPMI, no other selector is predefined so trying to use selector 0xB800 to
  920. access color video memory will generate a GP fault.
  921.  
  922. Note: Even when not running under DPMI, code which uses selector 0 to
  923. access the BIOS data area will generate a GP fault.  This is because
  924. selector 0 is a special NULL selector that cannot be read from or written
  925. to.
  926.  
  927. Under DPMI it is necessary to use the ExoProtectedPtr() function to create
  928. a selector which points to a physical memory location such as segment
  929. 0xB800.  It is recommended that you use ExoProtectedPtr() for maximum
  930. portability since it also works when not running under DPMI.  Simply pass
  931. ExoProtectedPtr() a real mode pointer to a physical memory address in the
  932. lower 1 MB and a size.  It will return a pointer to that memory address.
  933. The size parameter determines the size of the protected mode segment that
  934. the selector points to.  Attempting to access an offset greater than the
  935. size of the segment will generate a GP fault; again, a very good
  936. protection against writing to memory outside of a designated range.
  937.  
  938.  
  939.  
  940. Question: How do I call an interrupt in real mode?
  941.  
  942. Answer: If the interrupt you are calling is a documented DOS interrupt, it
  943. will be handled transparently by ExoSpace.  In addition, some interrupts
  944. which are not normally handled transparently by ExoSpace will be handled
  945. if the application is linked with one of the ExoSpace packages.  For
  946. example, ExoSpace does not handle the mouse interrupt transparently unless
  947. you link in the mouse package with the command "EXOSPACE PACKAGE MOUSE".
  948.  
  949. Interrupts which do not pass pointers to data, but only pass values in
  950. registers can be called from protected mode with no modifications to your
  951. code.  This works because ExoSpace will trap the interrupt, check to see
  952. if it is a special case which ExoSpace handles, and if not, it will
  953. reissue the interrupt in real mode.  The only problems occur when the real
  954. mode interrupt expects a pointer to a data buffer to be in a register pair
  955. such as ES:DI.  When the interrupt is reissued in real mode the pointer is
  956. no longer valid because it was a protected mode pointer and it will
  957. instead point to garbage in the first 1 MB.
  958.  
  959. To issue an interrupt you can use C's int86..() functions or ExoSpace's
  960. ExoRMInterrupt() function.  ExoSpace's ExoRMInterrupt() function should be
  961. slightly faster in most circumstances.
  962.  
  963.  
  964.  
  965. Question: How do I pass a pointer to data to a real mode interrupt?
  966.  
  967. Answer: You can use the ExoRealPtr() function to convert a protected mode
  968. pointer to a real mode pointer.  The return value from ExoRealPtr() should
  969. be loaded into the REGS structure that ExoRMInterrupt() or int86..() uses.
  970. The protected mode pointer must point to a memory location within the
  971. first 1 MB.
  972.  
  973.  
  974.  
  975. Question: How do I allocate a block of memory so that I know it is in the
  976. first 1 MB and therefore addressable in real mode?
  977.  
  978. Answer: Use the _xalloclow() function to allocate memory in the lower 1
  979. MB.  This is only needed for buffers that are passed to real mode
  980. interrupt handlers which can only address the first 1 MB.  Use _xfreelow()
  981. to free the allocated memory.
  982.  
  983. It is recommended that your code allocate and then free low DOS memory
  984. after every use to keep the amount of allocated low DOS memory in use at
  985. any one time down to a minimum.  Currently, _xalloclow() will steal memory
  986. from Clipper if it must to meet the request.  Allocating a great deal of
  987. low DOS memory could adversely affect performance.
  988.  
  989.  
  990.  
  991. Question: How can I have the user reserve an amount of low DOS memory for
  992. allocation by my program/library?
  993.  
  994. Answer: ExoSpace has added the LOWMEM parameter to the CLIPPER environment
  995. variable.  This parameter specifies the amount of low DOS memory to
  996. reserve for allocation with _xalloclow().  If your program/library
  997. allocates up to 25K at one time with _xalloclow(), the user could specify
  998. a LOWMEM parameter of 25K.  Actually, it is recommended at this time that
  999. you ignore the LOWMEM parameter due to the design of ExoSpace's low DOS
  1000. memory allocation scheme, but this may change in the future or a particular
  1001. end-users needs may require the LOWMEM parameter.
  1002.  
  1003.  
  1004.  
  1005. Question: How do I install an interrupt handler?
  1006.  
  1007. Answer: In most cases you can install a software interrupt handler using
  1008. the DOS function 0x25.  This requires no changes to your source code.
  1009. Conflicts can occur when installing hardware interrupt handlers.  ExoSpace
  1010. handles hardware interrupts in various ways and it is beyond the scope of
  1011. this document to discuss hardware interrupts.  If you are installing a
  1012. hardware interrupt, see if it works.  If it doesn't, contact us.  If it
  1013. does work be aware that hardware interrupts that occur frequently such as
  1014. serial port interrupts may degrade system performance and even come too
  1015. fast to be handled properly without special programming.  If you are
  1016. dealing with serial hardware interrupts or other fast hardware interrupts
  1017. you are probably a candidate for the full version of DOS/16M.  It contains
  1018. more documentation and example code for handling fast hardware interrupts.
  1019.  
  1020.  
  1021.  
  1022. Question: How can I allocate and use more than 64K at one time?
  1023.  
  1024. Answer:  Currently, there is no documented ExoSpace API function to do
  1025. this.  The DOS memory allocation function can allocate more than 64K at
  1026. one time, but only the first 64K can be addressed by the returned
  1027. selector.  A special kind of selector arithmetic must be done to address
  1028. data beyond the first 64K.  A future API revision may include functions to
  1029. use more than 64K of data, but for now it is best to allocate large
  1030. amounts of memory in 64K chunks.
  1031.  
  1032.  
  1033.  
  1034.  
  1035. Sample Code
  1036. -----------
  1037.  
  1038. We have provided some sample code with this draft API.  Additional code
  1039. samples will be forthcoming in the next two weeks.
  1040.  
  1041.  
  1042.